package com.pxl.springbootinit.service.impl;

import cn.hutool.core.collection.ConcurrentHashSet;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pxl.springbootinit.common.ErrorCode;
import com.pxl.springbootinit.constant.UserConstant;
import com.pxl.springbootinit.exception.BusinessException;
import com.pxl.springbootinit.model.dto.user.UserFrom;
import com.pxl.springbootinit.model.entity.User;
import com.pxl.springbootinit.model.vo.LoginUserVO;
import com.pxl.springbootinit.model.vo.UserVO;
import com.pxl.springbootinit.service.UserService;
import com.pxl.springbootinit.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @description 针对表【user】的数据库操作Service实现
 * @createDate 2024-12-20 10:02:04
 */
@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Resource
    private PasswordEncoder passwordEncoder;


    /**
     * 获取当前登录用户
     *
     * @param request HttpServletRequest
     * @return 当前登录的用户
     */
    @Override
    public User getLoginUser(HttpServletRequest request) {
        // 从session中获取当前登录用户
        Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        User currentUser = (User) userObj;

        // 判断是否存在登录用户
        if (currentUser == null || currentUser.getId() == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }

        // 从数据库查询（为了性能可以注释掉，直接走缓存）
        long userId = currentUser.getId();
        currentUser = this.getById(userId);

        // 用户不存在
        if (currentUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        return currentUser;
    }

    /**
     * 用户注册
     *
     * @param userAccount  用户账号
     * @param userPassword 用户密码
     * @param checkPassword 确认密码
     * @return 用户id
     */
    @Override
    public long userRegister(String userAccount, String userPassword, String checkPassword) {
        // 校验输入
        if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过短");
        }
        if (userPassword.length() < 8 || checkPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码过短");
        }

        // 校验密码是否一致
        if (!userPassword.equals(checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次输入的密码不一致");
        }

        synchronized (userAccount.intern()) {
            // 校验账号是否重复
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("user_account", userAccount);
            long count = this.baseMapper.selectCount(queryWrapper);
            if (count > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
            }

            // 密码加密
            String encryptPassword = passwordEncoder.encode(userPassword);

            // 保存用户信息
            User user = new User();
            user.setUserAccount(userAccount);
            user.setPassword(encryptPassword);
            boolean saveResult = this.save(user);

            if (!saveResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "注册失败，数据库错误");
            }
            return user.getId();
        }
    }

    /**
     * 用户登录
     *
     * @param userAccount 用户账号
     * @param userPassword 用户密码
     * @param request HttpServletRequest
     * @return 登录用户的信息
     */
    @Override
    public LoginUserVO userLogin(String userAccount, String userPassword, HttpServletRequest request) {
        // 校验输入
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号错误");
        }
        if (userPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");
        }

        // 查询用户是否存在
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("user_account", userAccount);
        User user = this.baseMapper.selectOne(queryWrapper);

        // 用户不存在
        if (user == null) {
            log.info("user login failed, userAccount cannot match userPassword");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或密码错误");
        }

        // 校验密码
        if (!passwordEncoder.matches(userPassword, user.getPassword())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");
        }

        // 设置用户登录状态到session
        request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, user);

        // 认证用户
        authenticateUser(user, request);

        user.setActiveStatus(1);
        this.updateById(user);

        // 返回登录用户的信息
        return this.getLoginUserVO(user);
    }

    /**
     * 用户登出操作
     *
     * @param request HttpServletRequest
     */
    @Override
    public boolean userLogout(HttpServletRequest request) {
        // 清除Spring Security中的认证信息
        SecurityContextHolder.clearContext();

        // 清除session中的用户信息
        HttpSession session = request.getSession();
        session.removeAttribute(UserConstant.USER_LOGIN_STATE);

        log.info("User has logged out successfully");
        return true;
    }

    /**
     * 设置用户的认证信息到Spring Security上下文
     *
     * @param user 登录的用户
     * @param request HttpServletRequest
     */
    private void authenticateUser(User user, HttpServletRequest request) {
        // 获取用户角色，确保加上 ROLE_ 前缀
        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority("ROLE_" + user.getRole())); // 加上 ROLE_ 前缀

        // 创建认证令牌
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(user.getUserAccount(), user.getPassword(), authorities);

        // 将认证信息设置到 SecurityContextHolder
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
    }


    /**
     * 获取登录用户的VO对象
     *
     * @param user 用户实体
     * @return LoginUserVO
     */
    @Override
    public LoginUserVO getLoginUserVO(User user) {
        if (user == null) {
            return null;
        }
        LoginUserVO loginUserVO = new LoginUserVO();
        BeanUtils.copyProperties(user, loginUserVO);
        return loginUserVO;
    }

    /**
     * 获取用户列表
     *
     * @param userFrom 查询条件
     * @return 用户列表
     */
    @Override
    public Page<UserVO> getUserList(UserFrom userFrom) {
        int pageSize = userFrom.getPageSize();
        int current = userFrom.getCurrent();

        // 校验参数
        if (pageSize < 1 || current < 1) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数错误");
        }

        // 分页查询用户
        Page<User> userPage = new Page<>(current, pageSize);
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.like(userFrom.getUserAccount() != null,"user_account", userFrom.getUserAccount());
        userQueryWrapper.orderByDesc("updated_time");
        Page<User> page = this.page(userPage, userQueryWrapper);

        // 转换为VO
        Page<UserVO> userVOPage = new Page<>();
        userVOPage.setTotal(page.getTotal());
        userVOPage.setPages(page.getPages());

        List<UserVO> userVOList = page.getRecords().stream().map(this::getUserVO).collect(Collectors.toList());
        userVOPage.setRecords(userVOList);

        return userVOPage;
    }

    /**
     * 根据用户ID获取用户信息
     *
     * @param id 用户ID
     * @return 用户信息VO
     */
    @Override
    public UserVO getUserById(Long id) {
        if (id == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数错误");
        }
        return getUserVO(this.getById(id));
    }

    /**
     * 更新用户信息
     *
     * @param userFrom 更新的用户信息
     * @return 是否更新成功
     */
    @Override
    public boolean updateUser(UserFrom userFrom) {
        User user = new User();
        user.setId(userFrom.getId());
        user.setUsername(userFrom.getUsername());
        user.setEmail(userFrom.getEmail());
        user.setPhone(userFrom.getPhone());
        user.setRealName(userFrom.getRealName());
        user.setIdCard(userFrom.getIdCard());
        user.setAvatarUrl(userFrom.getAvatarUrl());
        user.setAddress(userFrom.getAddress());
        user.setStatus(userFrom.getStatus());
        return this.updateById(user);
    }

    /**
     * 删除用户
     *
     * @param id 用户ID
     * @return 是否删除成功
     */
    @Override
    public boolean deleteUser(Long id) {
        return this.removeById(id);
    }

    /**
     * 将User对象转换为UserVO对象
     *
     * @param user 用户实体
     * @return 用户VO对象
     */
    @Override
    public UserVO getUserVO(User user) {
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(user, userVO);
        return userVO;
    }

    @Override
    public List<UserVO> getUserListByIdCard(UserFrom userFrom) {
        if (userFrom == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数错误");
        }
        String idCard = userFrom.getIdCard();
        if (idCard == null){
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.likeRight("id_card",idCard);
        return this.list(queryWrapper).stream().map(this::getUserVO).collect(Collectors.toList());
    }

    @Override
    public Long getTodayActiveCount() {
        return this.count(new QueryWrapper<User>().eq("active_status",1));
    }

    @Override
    public void resetUserActiveInfo() {
        List<User> list = this.list();
        list.forEach(user -> {
            user.setActiveStatus(0);
        });
        this.updateBatchById(list);
    }

    @Override
    public Page<UserVO> getUserExamine(UserFrom userFrom) {
        int pageSize = userFrom.getPageSize();
        int current = userFrom.getCurrent();

        // 校验参数
        if (pageSize < 1 || current < 1) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数错误");
        }

        // 分页查询用户
        Page<User> userPage = new Page<>(current, pageSize);
        QueryWrapper<User> userQueryWrapper = new QueryWrapper<>();
        userQueryWrapper.like(userFrom.getUserAccount() != null,"user_account", userFrom.getUserAccount());
        userQueryWrapper.isNotNull("id_card");
        userQueryWrapper.isNotNull("real_name");
        userQueryWrapper.orderByDesc("updated_time");
        Page<User> page = this.page(userPage, userQueryWrapper);

        // 转换为VO
        Page<UserVO> userVOPage = new Page<>();
        userVOPage.setTotal(page.getTotal());
        userVOPage.setPages(page.getPages());

        List<UserVO> userVOList = page.getRecords().stream().map(this::getUserVO).collect(Collectors.toList());
        userVOPage.setRecords(userVOList);

        return userVOPage;
    }
}
